package com.motlepluslong.controller;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.text.Normalizer;
import java.util.ArrayList;
import java.util.Iterator;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.motlepluslong.model.Dictionnary;
import com.motlepluslong.model.Game;

/**
 * Servlet implementation class ActionController
 */
@WebServlet("/actioncontroller.jsp")
public class ActionController extends HttpServlet {
	private static final long serialVersionUID = 1L;

	/**
	 * @see HttpServlet#HttpServlet()
	 */
	public ActionController() {
		super();
		// TODO Auto-generated constructor stub
	}

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		this.actionDispatcher(request,response);
	}

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		this.actionDispatcher(request,response);
	}

	/**
	 * Get a dictionnary in context or create if not exist !
	 * @return Dictionnary
	 */
	private Dictionnary getDictionnary(HttpServletRequest request)
	{
		Dictionnary dict;
		dict = (Dictionnary) this.getServletContext().getAttribute("dictionnary");
		if(dict == null)
		{
			dict = new Dictionnary();
			this.initDictionnary(dict, request);
			this.getServletContext().setAttribute("dictionnary",dict);
		}
		return dict;
	}
	/**
	 * Permet d'initialiser le dictionnaire
	 * @param dict
	 * @param request
	 */
	private void initDictionnary(Dictionnary dict, HttpServletRequest request){
		String path = request.getServletContext().getRealPath(dict.getPATH());
		BufferedReader in;
		//Init arrayList
		for(int i =0;i<10;i++)
			dict.getListWords().add(i,new ArrayList<String>());
		try {
			in = new BufferedReader(new FileReader(path));
			String l = null;
			while ((l = in.readLine() ) != null) {
				if(l != null){
					int nbChar = l.length();
					if(nbChar <=10){
						// Source :  http://www.developpez.net/forums/d460531/java/general-java/langage/supprimer-accents-chaine/
						l =  Normalizer.normalize(l, Normalizer.Form.NFD).replaceAll("[\u0300-\u036F]", "");
						dict.getListWords().get(nbChar-1).add(l);
					}
				}
			}
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	/**
	 * Dispatch the action of the controller
	 * @param request
	 * @param response
	 * @throws IOException 
	 * @throws ServletException 
	 */
	private void actionDispatcher(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
		Dictionnary dict = this.getDictionnary(request);
		String action = request.getParameter("action");
		if(action != null)
		{
			if(action.equals("startGame")){
				this.startGame(request);
				request.getRequestDispatcher("./game.jsp").forward(request, response);
			}else if(action.equals("addWords")){
				this.addWordProcess(dict, request);
				request.getRequestDispatcher("./game.jsp").forward(request, response);
			}else if(action.equals("reloadGame")){
				request.getSession().setAttribute("game", null);
				this.startGame(request);
				request.getRequestDispatcher("./game.jsp").forward(request, response);
			}
		}
	}

	/**
	 * Create and initialize the game.
	 * @param request
	 */
	private void startGame(HttpServletRequest request){
		Game game = (Game) request.getSession().getAttribute("game");
		if(game == null){
			game = new Game();
			request.getSession().setAttribute("game", game);
			for(int i = 0;i<26;i++)
				game.getNbLetters()[i]=0;
			String vowel = "aeiouy";
			char c;
			for(int i = 0;i<10;i++){
				//On force 4 voyelles
				if(i<4){
					c = vowel.charAt((int) (Math.random()*6));
				}else{
					c = (char) (Math.random() * 26 +'a');
				}
				//On prend le numero du charatère et si il y en à un alors on incremente la valeur.
				game.getNbLetters()[c-97]++;
				game.getLetters()[i] = c;				
			}
			this.searchLongestWordPossible(request, (Dictionnary) this.getServletContext().getAttribute("dictionnary"));
		}
	}

	/**
	 * Processus d'ajout d'un mot proposée par un joueur.
	 * @param dict
	 * @param request
	 */
	private void addWordProcess(Dictionnary dict, HttpServletRequest request){
		System.out.println("Process AddWord");
		String word = request.getParameter("words");
		//Mets en minuscule et retire les accents.
		word = word.toLowerCase();
		word = Normalizer.normalize(word, Normalizer.Form.NFD).replaceAll("[\u0300-\u036F]", "");
		//|||
		Game game = (Game) request.getSession().getAttribute("game");
		if(word != null && game != null ){
			if(!this.checkIfWordsIsAlreadyPlay(game.getWords(), word)){
				game.getWords()[game.getPlayed()] = word;
				if(this.lettersIsInWord(game, word)){
					if(this.wordsIsInDictionnary(word, dict)){
						game.getScoreByWords()[game.getPlayed()] = word.length();
						System.out.println("Mot OK");
					}else
						System.out.println("Mot pas dans dico");
				}else
					System.out.println("Mot qui ne convient pas avec le tableau de lettre");
				game.setPlayed(game.getPlayed()+1);
			}else{
				request.setAttribute("existWord",word);//On indique que le mot existe déjà.
			}
		}

	}

	/**
	 * Check if word is in dictionnary
	 * @param word
	 * @param dict
	 * @return boolean
	 */
	private boolean wordsIsInDictionnary(String word, Dictionnary dict){
		Iterator<String> it = dict.getListWords().get(word.length()-1).iterator();
		boolean check = false;
		while (it.hasNext()) {
			String wordDict = (String) it.next();
			if(word.equals(wordDict))
				check = true;
		}
		return check;
	}

	/**
	 * Check if is in array letters
	 * @param game
	 * @param word
	 * @return
	 */
	private boolean lettersIsInWord(Game game,String word){
		int i=0,sizeWord = word.length();
		Integer[] tabNbLetters = game.getNbLetters().clone();
		while(i<sizeWord){
			char c = word.charAt(i); 
			if(tabNbLetters[c-97] != 0)	
				tabNbLetters[c-97]--;
			else
				break;
			i++;
		}
		if(sizeWord-i == 0)
			return true;
		else
			return false;
	}

	/**
	 * Check if words is already play by player.
	 * @param words
	 * @param word
	 * @return boolean
	 */
	private boolean checkIfWordsIsAlreadyPlay(String[] words, String word){
		int i = 0;
		boolean exist = false; 
		while(i <= 5 && words[i] != null && !exist){
			if(words[i].equals(word))
				exist = true;System.out.println("Mot dans la liste");				
				i++;
		}
		return exist;
	}

	/**
	 * Research process of the longest word
	 * @param request
	 * @param dict
	 */
	private void searchLongestWordPossible(final HttpServletRequest request, final Dictionnary dict){
		Thread search = new Thread("search"){			
			public void run(){
				String word ="";
				int i = 9;

				if(request.getSession() != null && dict != null){
					Game game = (Game) request.getSession().getAttribute("game");
					if(game != null){
						while(word.equals("") && i >0){
							Iterator<String> it = dict.getListWords().get(i).iterator();
							while(it.hasNext() && word.equals(""))
							{
								String dWord = (String) it.next();
								if(ActionController.this.lettersIsInWord(game, dWord)){
									word = dWord;System.out.println("Mot trouvé : "+word);	
								}
							}
							i--;
						}
						if(word.equals(""))
							System.out.println("Pas de mot le plus long trouvé");
						game.setLongestWord(word);
					}
				}
			}
		};
		search.start();
		request.getSession().setAttribute("tSearch", search);
	}
}
